package com.xiyou.weblog.admin.config;

import com.xiyou.weblog.jwt.filter.JwtAuthenticationFilter;
import com.xiyou.weblog.jwt.filter.TokenAuthenticationFilter;
import com.xiyou.weblog.jwt.handler.RestAccessDeniedHandler;
import com.xiyou.weblog.jwt.handler.RestAuthenticationEntryPoint;
import com.xiyou.weblog.jwt.handler.RestAuthenticationFailureHandler;
import com.xiyou.weblog.jwt.handler.RestAuthenticationSuccessHandler;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.dao.DaoAuthenticationProvider;
import org.springframework.security.config.annotation.authentication.configuration.AuthenticationConfiguration;
import org.springframework.security.config.annotation.method.configuration.EnableMethodSecurity;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configurers.AbstractHttpConfigurer;
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.core.userdetails.UserDetailsService;

import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.web.SecurityFilterChain;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;


@Configuration
@Slf4j
@EnableMethodSecurity//代替@EnableGlobalMethodSecurity(prePostEnabled = true, securedEnabled = true)
public class WebSecurityConfig {

    // 用户登录服务
    @Resource
    private  UserDetailsService userDetailsService;
    // 用户认证校验失败处理器
    @Resource
    private  RestAuthenticationFailureHandler restAuthenticationFailureHandler;
    // 用户认证校验成功处理器
    @Resource
    private  RestAuthenticationSuccessHandler restAuthenticationSuccessHandler;
    // 加密算法
    @Resource
    private  PasswordEncoder passwordEncoder;


    //处理用户未登录访问受保护的资源的情况
    @Resource
    private RestAuthenticationEntryPoint authenticationEntryPoint;
    //处理登录成功后访问受保护的资源，但是权限不够的情况
    @Resource
    private RestAccessDeniedHandler deniedHandler;

    /**
     * 配置认证管理器
     */
    @Bean
    public AuthenticationManager authenticationManager(AuthenticationConfiguration authenticationConfiguration) throws Exception {
        DaoAuthenticationProvider provider = new DaoAuthenticationProvider();
        provider.setUserDetailsService(userDetailsService);
        provider.setPasswordEncoder(passwordEncoder);
        return authenticationConfiguration.getAuthenticationManager();
    }

    /**
     * 配置认证过滤器
     */
    @Bean
    public JwtAuthenticationFilter jwtAuthenticationFilter(AuthenticationManager authenticationManager) throws Exception {
        JwtAuthenticationFilter jwtAuthenticationFilter = new JwtAuthenticationFilter();
        jwtAuthenticationFilter.setAuthenticationManager(authenticationManager);
        jwtAuthenticationFilter.setAuthenticationSuccessHandler(restAuthenticationSuccessHandler);
        jwtAuthenticationFilter.setAuthenticationFailureHandler(restAuthenticationFailureHandler);
        return jwtAuthenticationFilter;
    }

    /**
     * Token 校验过滤器
     */
    @Bean
    public TokenAuthenticationFilter tokenAuthenticationFilter(){
        return new TokenAuthenticationFilter();
    }

    @Bean
    public SecurityFilterChain securityFilterChain(HttpSecurity http,AuthenticationManager authenticationManager,JwtAuthenticationFilter jwtAuthenticationFilter,TokenAuthenticationFilter tokenAuthenticationFilter) throws Exception {

        log.info("------------SecurityFilterChain------------");


        http
                .exceptionHandling(exceptionHandling -> exceptionHandling
                        // 处理用户未登录访问受保护的资源的情况
                        .authenticationEntryPoint(authenticationEntryPoint)
                        // 处理登录成功后访问受保护的资源，但是权限不够的情况
                        .accessDeniedHandler(deniedHandler))
                .authorizeHttpRequests(authorize ->
                        // 认证所有以 /admin 为前缀的 URL 资源
                        authorize.requestMatchers("/admin/**").authenticated()
                                // 其他都需要放行，无需认证
                                .anyRequest().permitAll())
                .addFilterBefore(jwtAuthenticationFilter,UsernamePasswordAuthenticationFilter.class)
                // 将 Token 校验过滤器添加到用户认证过滤器之前
                .addFilterBefore(tokenAuthenticationFilter,UsernamePasswordAuthenticationFilter.class)
                .authenticationManager(authenticationManager)
                // 禁用表单登录
                .formLogin(AbstractHttpConfigurer::disable)
                // 禁用rememberMe
                .rememberMe(AbstractHttpConfigurer::disable)
                // 关闭csrf
                .csrf(AbstractHttpConfigurer::disable)
                // 前后端分离，无需创建会话
                .sessionManagement(smc -> smc.sessionCreationPolicy(SessionCreationPolicy.STATELESS));

        return http.build();
    }


}
